﻿// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX - License - Identifier: Apache - 2.0

namespace HighLevelQueryAndScanExample
{
  using System;
  using System.Collections.Generic;
  using System.Threading.Tasks;
  using Amazon.DynamoDBv2;
  using Amazon.DynamoDBv2.DataModel;
  using Amazon.DynamoDBv2.DocumentModel;

  // snippet-start:[dynamodb.dotnet35.HighLevelQueryAndScan]

  /// <summary>
  /// Shows how to perform high level query and scan operations to Amazon
  /// DynamoDB tables. This example was created using the AWSSDK for .NET
  /// version 3.7 and .NET Core 5.0.
  /// </summary>
  public class HighLevelQueryAndScan
  {
    public static async Task Main(string[] args)
    {
      var client = new AmazonDynamoDBClient();

      DynamoDBContext context = new DynamoDBContext(client);

      // Get an item.
      await GetBook(context, 101);

      // Sample forum and thread to test queries.
      string forumName = "Amazon DynamoDB";
      string threadSubject = "DynamoDB Thread 1";

      // Sample queries.
      await FindRepliesInLast15Days(context, forumName, threadSubject);
      await FindRepliesPostedWithinTimePeriod(context, forumName, threadSubject);

      // Scan table.
      await FindProductsPricedLessThanZero(context);
    }

    public static async Task GetBook(IDynamoDBContext context, int productId)
    {
      Book bookItem = await context.LoadAsync<Book>(productId);

      Console.WriteLine("\nGetBook: Printing result.....");
      Console.WriteLine($"Title: {bookItem.Title} \n ISBN:{bookItem.Isbn} \n No. of pages: {bookItem.PageCount}");
    }

    /// <summary>
    /// Queries a DynamoDB table to find replies posted within the last 15 days.
    /// </summary>
    /// <param name="context">The DynamoDB context used to perform the query.</param>
    /// <param name="forumName">The name of the forum we're interested in.</param>
    /// <param name="threadSubject">The thread object containing the query parameters.</param>
    public static async Task FindRepliesInLast15Days(
      IDynamoDBContext context,
      string forumName,
      string threadSubject)
    {
      string replyId = $"{forumName} #{threadSubject}";
      DateTime twoWeeksAgoDate = DateTime.UtcNow - TimeSpan.FromDays(15);

      List<object> times = new List<object>();
      times.Add(twoWeeksAgoDate);

      List<ScanCondition> scs = new List<ScanCondition>();
      var sc = new ScanCondition("LastPostedBy", ScanOperator.GreaterThan, times.ToArray());
      scs.Add(sc);

      var cfg = new DynamoDBOperationConfig
      {
        QueryFilter = scs,
      };

      AsyncSearch<Reply> response = context.QueryAsync<Reply>(replyId, cfg);
      IEnumerable<Reply> latestReplies = await response.GetRemainingAsync();

      Console.WriteLine("\nReplies in last 15 days:");

      foreach (Reply r in latestReplies)
      {
        Console.WriteLine($"{r.Id}\t{r.PostedBy}\t{r.Message}\t{r.ReplyDateTime}");
      }
    }

    /// <summary>
    /// Queries for replies posted within a specific time period.
    /// </summary>
    /// <param name="context">The DynamoDB context used to perform the query.</param>
    /// <param name="forumName">The name of the ofrum we're interested in.</param>
    /// <param name="threadSubject">Information about the subject we are
    /// interested in.</param>
    public static async Task FindRepliesPostedWithinTimePeriod(
      IDynamoDBContext context,
      string forumName,
      string threadSubject)
    {
      string forumId = forumName + "#" + threadSubject;
      Console.WriteLine("\nReplies posted within time period:");

      DateTime startDate = DateTime.UtcNow - TimeSpan.FromDays(30);
      DateTime endDate = DateTime.UtcNow - TimeSpan.FromDays(1);

      List<object> times = new List<object>();
      times.Add(startDate);
      times.Add(endDate);

      List<ScanCondition> scs = new List<ScanCondition>();
      var sc = new ScanCondition("LastPostedBy", ScanOperator.Between, times.ToArray());
      scs.Add(sc);

      var cfg = new DynamoDBOperationConfig
      {
        QueryFilter = scs
      };

      AsyncSearch<Reply> response = context.QueryAsync<Reply>(forumId, cfg);
      IEnumerable<Reply> repliesInAPeriod = await response.GetRemainingAsync();

      foreach (Reply r in repliesInAPeriod)
      {
        Console.WriteLine("{r.Id}\t{r.PostedBy}\t{r.Message}\t{r.ReplyDateTime}");
      }
    }

    /// <summary>
    /// Queries the DynamoDB ProductCatalog table for products costing less
    /// than zero.
    /// </summary>
    /// <param name="context">The DynamoDB context object used to perform the
    /// query.</param>
    public static async Task FindProductsPricedLessThanZero(IDynamoDBContext context)
    {
      int price = 0;

      List<ScanCondition> scs = new List<ScanCondition>();
      var sc1 = new ScanCondition("Price", ScanOperator.LessThan, price);
      var sc2 = new ScanCondition("ProductCategory", ScanOperator.Equal, "Book");
      scs.Add(sc1);
      scs.Add(sc2);

      AsyncSearch<Book> response = context.ScanAsync<Book>(scs);

      IEnumerable<Book> itemsWithWrongPrice = await response.GetRemainingAsync();

      Console.WriteLine("\nFindProductsPricedLessThanZero: Printing result.....");

      foreach (Book r in itemsWithWrongPrice)
      {
        Console.WriteLine($"{r.Id}\t{r.Title}\t{r.Price}\t{r.Isbn}");
      }
    }
  }

  // snippet-end:[dynamodb.dotnet35.HighLevelQueryAndScan]
}
